using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Framework.Serialization;
using IQIGame.Onigao.Game;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public class EntityBehavScriptComponent : TReusableEvtComponent
    {
        private ConfigBehavScript _scriptCfg;
        private ConfigBehavScriptNode _curNodeCfg;
        private Vector3 _initEntityPos;
        private string behavScriptName;
        private EntityAutoNavigationComponent _navigationCom;
        private uint _curTimer;
        private bool _isInterrupted;

        public override uint MaxStore => 100;

        public override void OnCreate(TEntity entity)
        {
            base.OnCreate(entity);
            _navigationCom = _entity.GetComponent<EntityAutoNavigationComponent>(ETComponentType.EntityNavigation);
            if (_navigationCom == null)
            {
                _navigationCom = _entity.AddComponentWithPool<EntityAutoNavigationComponent>(ETComponentType.EntityNavigation);
            }
        }

        public void Play(string behavScriptName)
        {
            Stop();
            InnerPlay(behavScriptName).Forget();
        }

        private async UniTaskVoid InnerPlay(string behavScriptName)
        {
            if (string.IsNullOrEmpty(behavScriptName))
            {
                return;
            }
            if (this.behavScriptName == behavScriptName)
            {
                return;
            }
            var resLoader = ResLoader.Create();
            var txtAsset = await resLoader.LoadABAssetAwait<TextAsset>(PathConstant.GetBehavScriptPath(behavScriptName));
            if (txtAsset == null)
            {
                LogGame.LogError($"读取配置[{behavScriptName}]失败，配置为空!");
                resLoader.Put2Pool();
                return;
            }
            ByteBuf buf = new ByteBuf(txtAsset.bytes);
            _scriptCfg = buf.DeSerializeObject<ConfigBehavScript>();
            resLoader.Put2Pool();

            _curNodeCfg = _scriptCfg.GetStartNode();
            _initEntityPos = _entity.unityPosOfData;
            this.behavScriptName = behavScriptName;

            DoAction().Forget();
        }

        /// <summary>
        /// 执行当前动作
        /// </summary>
        /// <returns></returns>
        private async UniTaskVoid DoAction()
        {
            bool isSuccess = false;
            //执行动作
            if (_curNodeCfg is ConfigBSNodeAnimation cfgAnim)
            {
                isSuccess = PlayAnimation(cfgAnim.actionCid);
                _curTimer = ManagerCenter.Timer.StartOneTimer(cfgAnim.duration.MillisecToSec());
                await _curTimer.AwaitTimer();
                _curTimer = 0;
            }
            else if (_curNodeCfg is ConfigBSNodeNavigation cfgNavi)
            {
                Vector3 refPos = cfgNavi.isRelativePos ? _initEntityPos : Vector3.zero;
                isSuccess = await NavigateTo(refPos + cfgNavi.targetUnityPos);
            }
            //!isSuccess：播放动作失败，或寻路失败，或寻路被打断，不再继续，!isSuccess后不要调用Break/Stop/ClearScriptData，
            //因为Break自身就会导致本次动作执行失败，而如果在预期之外执行失败，那么该组件处于corrupted状态，不影响重启和销毁，但需保留数据以便恢复继续。
            //_isInterrupted：await后如果处于打断状态不再继续处理
            if (!isSuccess || _isInterrupted)
            {
                return;
            }
            //切换动作前的等待
            _curTimer = ManagerCenter.Timer.StartOneTimer(_curNodeCfg.switchDelay.MillisecToSec());
            await _curTimer.AwaitTimer();
            _curTimer = 0;
            //await后如果处于打断状态不再继续处理
            if (_isInterrupted)
            {
                return;
            }
            //正常流转到这里继续下一个动作
            NextAction();
        }

        /// <summary>
        /// 下一步
        /// </summary>
        private void NextAction()
        {
            if (_scriptCfg == null)
            {
                return;
            }
            if (_curNodeCfg.nextId > 0)
            {
                if (!_scriptCfg.nodes.TryGetValue(_curNodeCfg.nextId, out var nn))
                {
                    LogGame.LogError($"找不到下一个节点id：{_curNodeCfg.nextId}");
                    Stop();
                    return;
                }
                _curNodeCfg = nn;
                DoAction().Forget();
            }
            else //脚本结束
            {
                Stop();
            }
        }

        /// <summary>
        /// 打断（可恢复继续）
        /// </summary>
        public void Break()
        {
            if (_scriptCfg == null)
            {
                return;
            }
            _isInterrupted = true;
            StopTimer();
            _navigationCom?.Stop(true);
        }

        /// <summary>
        /// 从被打断的动作重新开始，并继续脚本
        /// </summary>
        public void Continue()
        {
            if (_scriptCfg == null)
            {
                return;
            }
            _isInterrupted = false;
            DoAction().Forget();
        }

        private void StopTimer()
        {
            if (_curTimer != 0)
            {
                _curTimer.StopTimer();
                _curTimer = 0;
            }
        }

        private bool PlayAnimation(int actionCid)
        {
            var animCom = _entity.GetComponent<EntityAnimationComponent>(ETComponentType.EntityAnimation);
            if (animCom == null)
            {
                LogGame.LogError($"脚本播放失败，尝试播放动画发现实体缺少动画组件。");
                return false;
            }
            animCom.StartAnimAction(actionCid);
            return true;
        }

        private async UniTask<bool> NavigateTo(Vector3 targetPos)
        {
            return await _navigationCom.NavigateTo(targetPos);
        }

        private void Stop()
        {
            StopTimer();
            _navigationCom.Stop(true);
            ClearScriptData();
        }

        private void ClearScriptData()
        {
            _scriptCfg = null;
            _curNodeCfg = null;
            _initEntityPos = default;
            behavScriptName = null;
            _curTimer = 0;
            _isInterrupted = false;
        }

        public override void OnPoolReset()
        {
            StopTimer();
            _navigationCom.ForceEndTask();
            ClearScriptData();
            _navigationCom = null;
        }
    }
}
